package com.lejin.service;

import com.lejin.dto.SearchDTO;
import com.lejin.entity.ESCourse;
import com.lejin.mapper.CourseMapper;

import com.lejin.vo.PageResultVO;
import com.lejin.vo.ResultVO;

import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SearchService implements ISearchService {

    @Autowired
    private CourseMapper courseMapper;


    @Autowired
    private ElasticsearchRestTemplate restTemplate;


    @Override
    public ResultVO init() {
        //1:查询课程信息
        List<ESCourse> courseCat = courseMapper.findCourseCat();

        System.out.println(courseCat);

        //2:删除索引库
        restTemplate.deleteIndex(ESCourse.class);

        //3:创建索引库
        restTemplate.createIndex(ESCourse.class);
        restTemplate.putMapping(ESCourse.class);

        //4:同步数据
        restTemplate.save(courseCat);


        return new ResultVO(true, "同步成功");


    }

    @Override
    public PageResultVO<ESCourse> search(SearchDTO searchDTO) {
        if (searchDTO == null) {
            return new PageResultVO<>(false, "非法参数");
        }
        String keyword = searchDTO.getKeyword();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (!StringUtils.isEmpty(keyword)) {

            MatchQueryBuilder outlineName = QueryBuilders.matchQuery("outlineName", keyword);
            boolQueryBuilder.should(outlineName);


            MatchQueryBuilder cat1name = QueryBuilders.matchQuery("cat1name", keyword);
            boolQueryBuilder.should(cat1name);

            MatchQueryBuilder cat2name = QueryBuilders.matchQuery("cat2name", keyword);
            boolQueryBuilder.should(cat2name);

        }
        //分页查询
        PageRequest pageRequest = PageRequest.of((searchDTO.getPage() - 1) < 0 ? 0 : (searchDTO.getPage() - 1), searchDTO.getSize());
        //设置高亮
        HighlightBuilder outlineNameHighlightBuilder = getHighlightBuider("outlineName");

        TermsAggregationBuilder cat1nameTermsAggregationBuilder = AggregationBuilders.terms("cat1name_agg").field("cat1name").size(100);
        //根据三级分类分桶
        TermsAggregationBuilder cat2nameTermsAggregationBuilder = AggregationBuilders.terms("cat2name_agg").field("cat2name").size(100);

        //根据一级分类过滤
        String cat1NameFilter = searchDTO.getCat1NameFilter();
        if(!StringUtils.isEmpty(cat1NameFilter)){
            TermQueryBuilder cat1name = QueryBuilders.termQuery("cat1name", cat1NameFilter);
            boolQueryBuilder.filter(cat1name);
        }
        String cat2NameFilter = searchDTO.getCat2NameFilter();
        if(!StringUtils.isEmpty(cat2NameFilter)){
            TermQueryBuilder cat2name = QueryBuilders.termQuery("cat2name", cat2NameFilter);
            boolQueryBuilder.filter(cat2name);
        }


        String priceSort = searchDTO.getPriceSort();
        FieldSortBuilder pricecFieldSortBuilder = null;
        if(!StringUtils.isEmpty(priceSort)){
            if("asc".equals(priceSort)){
                pricecFieldSortBuilder = SortBuilders.fieldSort("price").order(SortOrder.ASC);
            }else{
                pricecFieldSortBuilder = SortBuilders.fieldSort("price").order(SortOrder.DESC);
            }
        }


        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                //指定查询方式
                .withQuery(boolQueryBuilder)
                //指定分页信息
                .withPageable(pageRequest)
                //设置高亮
                .withHighlightBuilder(outlineNameHighlightBuilder)

                //设置分桶
                .addAggregation(cat1nameTermsAggregationBuilder)
                //设置三级分类分桶
                .addAggregation(cat2nameTermsAggregationBuilder);
        if (pricecFieldSortBuilder != null) {
            nativeSearchQueryBuilder.withSort(pricecFieldSortBuilder);


        }

        SearchHits<ESCourse> searchRes = restTemplate.search(nativeSearchQueryBuilder.build(), ESCourse.class);
        //获取总记录数
        long totalHits = searchRes.getTotalHits();
        //获取文档列表
        List<ESCourse> esCourseList = searchRes.getSearchHits().stream().map(hit -> {
            ESCourse content = hit.getContent();
        //获取高亮信息
            Map<String, List<String>> highlightFields = hit.getHighlightFields();
            highlightFields.forEach((k,v)->{
                if("outlineName".equals(k)){
                    content.setOutlineName(v.get(0));
                }
            });

            return content;
        }).collect(Collectors.toList());

        //获取分桶信息
        Aggregations aggregations = searchRes.getAggregations();
        Terms cat2name_agg = aggregations.get("cat2name_agg");
        List<String> cat2NameList = cat2name_agg.getBuckets().stream().map(item -> (String) item.getKey()).collect(Collectors.toList());

        //获取分桶信息（三级分类）
        Terms cat1name_agg = aggregations.get("cat1name_agg");
        List<String> cat1NameList = cat1name_agg.getBuckets().stream().map(item -> (String) item.getKey()).collect(Collectors.toList());





        PageResultVO<ESCourse> pageResultVO = new PageResultVO<>(true, "success");
        pageResultVO.setTotal(totalHits);
        pageResultVO.setData(esCourseList);
        pageResultVO.setCat1NameList(cat1NameList);
        pageResultVO.setCat2NameList(cat2NameList);


        return pageResultVO;

    }

    private HighlightBuilder getHighlightBuider(String... fields) {
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
        for (String field : fields) {
            highlightBuilder.field(field);//高亮查询字段
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("<span style=\"color:red\">");   //高亮设置
        highlightBuilder.postTags("</span>");
        //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段

        return highlightBuilder;
    }


}

